/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

import java.util.*;
import Util.*;
import java.util.ArrayList;

/**
 *
 * @author u61851
 */
public final class MaqCambio extends MaqAutomata {

    /**
     * Constructor de la maquina de cambio
     * @param m ArrayList de Moneda
     * @param b ArrayList de Billete
     */
    public MaqCambio(ArrayList<Moneda> m, ArrayList<Billete> b) {
        super(m, b);

        Hashtable<Dinero, Integer> ht = new Hashtable<Dinero, Integer>();

        Fondo f = new Fondo(ht); // fondo vacio
        Cambio c = new Cambio(ht); // cambio vacio
        Monto mon = new Monto(ht); // monto vacio

        this.setFondo(f); // fondo vacio
        this.setCambio(c); // cambio vacio
        this.setMonto(mon); // monto vacio

    }

    /**
     * @DEPRECATED
    public float ingresarImporte(ArrayList<Billete> importeIngresado) {
        // esto hay que agregarlo al monto ?
        float importe = 0;
        int cantidad = 0;
        Monto monto = this.getMonto(); // tomo el monto actual -- esto en realidad no sirve!
        Hashtable<Dinero, Integer> totalBilletes = new Hashtable<Dinero, Integer>();

        for (Billete b : importeIngresado) { // arraylist de billetes ingresados
            importe += b.getValor();
            if (totalBilletes.contains(b)) { // no se como actualizar un valor en el hashtable
                cantidad = (totalBilletes.get(b) + 1); // capturo la cantidad actual y le sumo 1
                totalBilletes.remove(b); // borro la entrada del ht
                totalBilletes.put(b, cantidad); // y la vuelvo a agregar con la cantidad
            } else {
                totalBilletes.put(b, new Integer(1));
            }
        }

        monto.setValores(totalBilletes);
        this.setMonto(monto); // reemplaza el monto anterior por el actual.

        return importe;
    }*/

    /**
     * Devuelve un Hashtable con el cambio en monedas
     * @param b Billete
     * @return Hashtable con el vuelto en monedas
     */
    public Hashtable<Dinero, Integer> darCambio(Billete b) {
        int cantidad = 0;
        int i = 0;
        float vuelto = b.getValor();
        Dinero din;
        Moneda mon;
        Hashtable<Dinero, Integer> vueltoMonedas = new Hashtable<Dinero, Integer>();

        Fondo f = this.getFondo(); // no son todo monedas!!

        Hashtable<Dinero, Integer> monedas = f.getValores(); // monedas que habilitadas en el fondo con su cantidad<Moneda, Cantidad>

        ArrayList<Moneda> monedasDisp = new ArrayList<Moneda>(); // monedas que tengo disponibles

        for (Enumeration e = f.getValores().keys(); e.hasMoreElements();) { // tengo que fijarme si es moneda o no! puede haber billetes!!
            din = (Dinero) e.nextElement();

            if (din.sosMoneda()) { // si es moneda la agrego al disponible
                mon = (Moneda) din;
                for (i = 0; i < monedas.get(mon); i++) { // agrego tantas monedas a la lista como monedas tenga
                    monedasDisp.add(mon); // monedas que tengo disponibles para dar el vuelto
                }
            }
        }

        Collections.sort(monedasDisp); // ordena las monedas de forma ascendente, esto es posible gracias a la implementacion de la interface Comparable por parte de la clase Dinero
        // y a overraidear el metodo compareTo.


        Moneda m;
        //for (Moneda m : monedasDisp) {
        for (int z = 0; z < monedasDisp.size() && vuelto > 0; z++) {
            m = monedasDisp.get(z);
            if (monedas.get(m) > 0 && vuelto >= m.getValor()) // si tengo cantidad de monedas y el vuelto es mayor al valor de la moneda
            {
                vuelto -= m.getValor(); // resto al vuelto el valor de la moneda
                if (vueltoMonedas.containsKey(m)) { // esto es lo mejor que se puede hacer??
                    cantidad = (vueltoMonedas.get(m) + 1);
                    vueltoMonedas.remove(m); // lo borro y lo vuelvo a agregar con el contenido correcto
                    vueltoMonedas.put(m, cantidad);
                } else {
                    vueltoMonedas.put(m, new Integer(1)); // si no esta (la primera vez) lo agrego y le pongo cantidad
                }
            }
        }

        if (vuelto > 0) {
            return null;
        } else {
            Hashtable<Dinero, Integer> mont = new Hashtable<Dinero, Integer>();
            mont.put(b, 1);

            Monto monto = new Monto(mont);
            this.setMonto(monto); // seteo el monto, y esto se agrega al fondo


            Cambio c = new Cambio(vueltoMonedas);
            this.setCambio(c); // seteo el cambio

            Date d = new Date(); // hoy

            int size = (this.getcAuditoria().size() + 1);
            Cinta cin = new Cinta(size, d, null, this.getCambio(), this.getMonto()); // creo la cinta y pongo el producto en null

            this.addcAuditoria(cin); // agrego la cinta de auditoria

            return c.getCambio();
        }
    }

    /**
     * Informa sobre el estado de situacion del Fondo, el Monto y el Cambio de la maquina
     */
    public void informeEstadoMaquina() {
        // total para el cambio
        Cambio cambio = this.getCambio();
        Hashtable<Dinero, Integer> dinero = cambio.getValores();

        float nTotal = 0;
        for (Enumeration e = dinero.keys(); e.hasMoreElements();) {
            Dinero din = (Dinero) e.nextElement();

            nTotal += dinero.get(din) * din.getValor();

        }

        System.out.println("Cambio es de: " + nTotal);
        this.mostrarCambio();

        // total para el fondo
        Fondo fondo = this.getFondo();
        dinero = fondo.getValores();

        nTotal = 0;
        for (Enumeration e = dinero.keys(); e.hasMoreElements();) {
            Dinero din = (Dinero) e.nextElement();

            nTotal += dinero.get(din) * din.getValor();

        }
        System.out.println("Fondo es de: " + nTotal);
        this.mostrarBilletesFondo();
        this.mostrarMonedasFondo();
        // total para el monto
        Monto monto = this.getMonto();
        dinero = monto.getValores();

        nTotal = 0;
        for (Enumeration e = dinero.keys(); e.hasMoreElements();) {
            Dinero din = (Dinero) e.nextElement();
            nTotal += dinero.get(din) * din.getValor();
        }
        System.out.println("Monto es de: " + nTotal);
        this.mostrarMonto();
    }

    /**
     * Para solicitar el Cambio en Monedas para un Billete
     */
    public void solicitarCambio() {
        Scanner in = new Scanner(System.in);

        //muestro los billetes
        this.mostrarBilletes();
        System.out.print("Ingrese el Billete: ");
        int codBillete = in.nextInt();
        Billete b = this.getBillete(codBillete);
        Hashtable<Dinero, Integer> vuelto = darCambio(b);
        if (vuelto != null) {
            for (Enumeration e = vuelto.keys(); e.hasMoreElements();) {
                Moneda m = (Moneda) e.nextElement();
                System.out.println("Moneda: valor: $" + m.getValor() + " cantidad de " + vuelto.get(m));
            }
        } else {
            System.out.println("Lo siento en este momento la maquina no dispone de monedas suficientes para dar cambio");
        }
    }

    /**
     * Muestra los componentes de la cinta de auditoria
     */
    public void mostrarCinta() {
        for (Cinta c : this.getcAuditoria()) {
            Cambio cam = c.getCambio();
            Hashtable<Dinero, Integer> camb = c.getCambio().getCambio();

            System.out.println("Transferencia: " + c.getNroTrans() + " en el dia " + c.getFechaTrans());
            float nTotal = 0;
            for (Enumeration e = camb.keys(); e.hasMoreElements();) {
                Moneda m = (Moneda) e.nextElement();
                System.out.println("Moneda: " + m.getValor() + " cantidad: " + camb.get(m));
                nTotal += camb.get(m) * m.getValor();

            }
            System.out.println("Monto: " + nTotal);

        }
    }

    /**
     * Muestra la cinta para el dia actual
     */
    public void informeDiarioMaquina() {
        System.out.println("Transferencias del dia de hoy");
        Date d = new Date(); // hoy
        d = new Date(d.getYear(), d.getMonth(), d.getDate());
        for (Cinta c : this.getcAuditoria()) {
            if (c.getFechaTrans().after(d)) {
                Enumeration e = c.getImporte().getValores().keys();
                System.out.println("Transferencia: " + c.getNroTrans());
                if (e.hasMoreElements()) {
                    Billete b = (Billete) e.nextElement();
                    b.getValor();
                    System.out.println(" Monto: " + b.getValor());

                }
            }
        }

    }

    /**
     * Metodo que inicia la simulacion de la maquina
     */
    public void iniciarSimulacion() {
        Scanner in = new Scanner(System.in);
        int opc = 0;
        boolean admin = false;
        System.out.println("===============\tSIMULACION: MAQUINA DAR CAMBIO\t===============");
        do {
            //++++++++++  Usuario  ++++++++++
            if (admin == false) {
                System.out.println("Menu de opciones:"
                        + "\n\t1. Solicitar Cambio"
                        + "\n\t2. Cambiar a usuario adminsitrador"
                        + "\n\t0. Terminar Simulacion");

                System.out.print("Ingrese la opcion que desea: ");
                opc = in.nextInt();

                switch (opc) {
                    case 1:
                        solicitarCambio();
                        break;
                    case 2:
                        System.out.print("Ingrese el password del administrador para cambiar el modo: ");
                        String pass = in.next();

                        if (pass.equals(MaqAutomata.getPwdAdmin())) {
                            admin = true;
                        } else {
                            System.out.println("Password INCORRECTO");
                        }

                        break;
                }
            } //++++++++++  Administrador  ++++++++++
            else {
                System.out.println("Menu de opciones:"//
                        + "\n\t1. Alta Monedas"
                        + "\n\t2. Informe estado de Maquina"
                        + "\n\t3. Informe diario de la maquina"
                        + "\n\t4. Informe de monedas"
                        + "\n\t5. Mostrar Cinta de Auditoria"
                        + "\n\t6. Cambiar a usuario comun"
                        + "\n\t7. Cambiar Password de Administrador"
                        + "\n\t0. Terminar Simulacion");
                System.out.print("Ingrese la opcion que desea: ");
                opc = in.nextInt();

                switch (opc) {
                    case 1:
                        this.agregarMonedasAFondo();
                        break;
                    case 2:
                        this.informeEstadoMaquina();
                        break;
                    case 3:
                        this.informeDiarioMaquina();
                        break;
                    case 4:
                        this.mostrarMonedasFondo();
                        break;
                    case 5:
                        this.mostrarCinta();
                        break;
                    case 6:
                        System.out.print("Se ha cambiado a usuario comun");
                        admin = false;
                        break;
                    case 7:
                        System.out.print("Ingrese el password del Administrador: ");
                        String pass = in.next();

                        if (pass.equals(MaqAutomata.getPwdAdmin())) {
                            System.out.print("Ingrese el nuevo password: ");
                            pass = in.next();
                            this.setPwdAdmin(pass);
                        } else {
                            System.out.println("Password INCORRECTO");
                        }
                        break;
                }
            }
        } while (opc != 0);
    }
}
